package com.globalwave.common.scheduling;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.globalwave.common.U;
import com.globalwave.common.cache.CodeHelper;
import com.globalwave.common.db.ConnectionProvider;
import com.globalwave.system.entity.TaskConfig;
import com.globalwave.system.entity.TaskLog;
import com.globalwave.system.entity.TaskLogCriterion;
import com.globalwave.system.service.TaskLogService;

public abstract class RunnableTask implements Runnable {

	private Log log = LogFactory.getLog(this.getClass()) ;

	private TaskConfig taskConfig ;
	private TaskLog taskLog ;
	private TaskLogService taskLogService ;
	private TaskContext context ;
	protected ConnectionProvider connectionProvider;
	
	@Override
	public void run() {
		if (log.isDebugEnabled()) {
		    log.debug(this.taskConfig.getCode_() + " will be Run!") ;
		}
		
        try{
        	init();
        	
    		if (isRunning()) {
    			log.error("Warning:" + this.taskConfig.getCode_() + " is Running! This task will be Cancel") ;
    			return ;
    		}

    		logStart() ;
    		
    		if (this.context == null) {
    			this.context = new TaskContext() ;
    		}
        	execute() ;

        	if(TaskLog.TASK_STATUS_RUNNING.equals(taskLog.getTask_status())) {
                logEnd() ;
        	} else {
        	    logBreakDown() ;   
        	}
        } catch(Exception e) {
			log.error("task " + this.taskConfig.getCode_() + " got some trouble! ", e) ;
			
			try {
                logException(e) ;
			} catch (Exception le) {
				//log.error("task log Excetipon! ", e) ;
				throw new RuntimeException(e) ;
			}
        } finally {
        	destroy();
        }
	}
	
	/**
	 * if isCanceled() then return ;
	 */
    public abstract void execute() throws Exception;
    
    public void init() throws Exception {
		taskLogService = (TaskLogService)CodeHelper.getAppContext().getBean("taskLogService") ;  
		connectionProvider = new ConnectionProvider();  	
    }
    
    /**
     * close connection 
     * release resource
     */
    public void destroy() {
    	taskLogService = null;
    	connectionProvider.closeAllConnection() ;
    	connectionProvider = null ;
    	taskLog = null ;
    }


    public TaskLog findLastTask() throws Exception {
    	
    	TaskLogCriterion criterion = new TaskLogCriterion() ;
    	criterion.setTask_config_id(taskConfig.getTask_config_id()) ;
    	
    	List<TaskLog> list = taskLogService.query(criterion, 1, 1, null) ;
    	
    	if (list.size() == 0) {
    		return null ;
    	} else {
    		return list.get(0) ;
    	}
    }


    public void reloadTaskLog() throws Exception {
    	
    	TaskLogCriterion criterion = new TaskLogCriterion() ;
    	criterion.setTask_log_id(taskLog.getTask_log_id()) ;
    	
    	List<TaskLog> list = taskLogService.query(criterion, 1, 1, null) ;
    	
    	taskLog = list.get(0) ;
    }
    
    private boolean isRunning() throws Exception {
    	TaskLog last = findLastTask() ;
    	if (last == null) {
    		return false ;
    	} else {
    		final String status = last.getTask_status() ;
    	    return TaskLog.TASK_STATUS_RUNNING.equals(status) // 正常运行..
    	    			|| TaskLog.TASK_STATUS_CANCELED.equals(status);// 正在中止中..
    	}
    }
    
    public boolean isCanceled() throws Exception {
    	reloadTaskLog() ;
    	return TaskLog.TASK_STATUS_CANCELED.equals(taskLog.getTask_status()) ;
    }
    
    private void logStart() throws Exception {
    	taskLog = new TaskLog() ;
    	taskLog.setTask_config_id(taskConfig.getTask_config_id()) ;
    	taskLog.setStart_on(U.currentTimestamp()) ; 
    	taskLog.setUpdate_on(taskLog.getStart_on()) ;
    	taskLog.setTask_status(TaskLog.TASK_STATUS_RUNNING) ;
    	taskLog.setApp_id((String)context.get("app_id")) ;
    	
    	taskLogService.create(taskLog) ;
    }
    
    private void logEnd() throws Exception {
    	taskLog.setEnd_on(U.currentTimestamp()) ; 
    	taskLog.setUpdate_on(taskLog.getEnd_on()) ;
    	taskLog.setTask_status(TaskLog.TASK_STATUS_SUCCESS) ;

    	taskLogService.update(taskLog) ;
    }
    
    private void logBreakDown() throws Exception {
    	taskLog.setEnd_on(U.currentTimestamp()) ; 
    	taskLog.setUpdate_on(taskLog.getEnd_on()) ;
    	taskLog.setTask_status(TaskLog.TASK_STATUS_BREAK_DOWN) ;
    	taskLog.setRemark_((String)context.get("remark")) ;

    	taskLogService.update(taskLog) ;
    }
    
    private void logException(Exception e) throws Exception {
    	taskLog.setEnd_on(U.currentTimestamp()) ; 
    	taskLog.setUpdate_on(taskLog.getEnd_on()) ;
    	taskLog.setTask_status(TaskLog.TASK_STATUS_FAIL) ;
    	String message = e.getMessage() ;
    	if (message.length() > 2500) {
    	    taskLog.setRemark_(message.substring(0, 2500)) ;
    	} else {
    	    taskLog.setRemark_(message);
    	}
    	
    	taskLogService.update(taskLog) ;
    }
    
    public void updateStatus() throws Exception {
    	taskLog.setUpdate_on(U.currentTimestamp()) ;
    	taskLog.setRemark_((String)context.get("remark")) ;
    	this.taskLogService.update(taskLog) ;
    }


	public TaskConfig getTaskConfig() {
		return taskConfig;
	}

	public void setTaskConfig(TaskConfig taskConfig) {
		this.taskConfig = taskConfig;
	}

	public TaskContext getContext() {
		return context;
	}

	public void setContext(TaskContext context) {
		this.context = context;
	}

	public void setTaskLogService(TaskLogService taskLogService) {
		this.taskLogService = taskLogService;
	}

	public TaskLog getTaskLog() {
		return taskLog;
	}
    
}
